import { _decorator, Component, director, Label, Node, Prefab } from 'cc';
import { CHANGE_BOARD, CHECK_CLEAR, CHECK_COMPLETE, CHECK_LOSED } from './Event';
import { GAME_EVENT_ENUM, GAME_SCENE_ENUM, GAME_STATUS_ENUM } from './Enum';
import { DataManager } from './DataManager';
import { levels } from './Level';
import { shuffle } from './Utils';
import { BlockType } from './type';
import { Block } from './Block';
const { ccclass, property } = _decorator;

@ccclass('GameManager')
export class GameManager extends Component {
    @property(Node)
    boardLevelNode: Node = null;
    @property(Node)
    boardLevelExtendNode: Node = null;
    @property(Node)
    boardRandomLeftNode: Node = null;
    @property(Node)
    boardRandomRightNode: Node = null;
    @property(Node)
    boardSlotNode: Node = null;
    @property(Node)
    boardHideNode: Node = null;
    @property(Prefab)
    blockPrefan: Prefab = null;
    @property(Label)
    titleLabel: Label = null;
    @property(Node)
    gameOverNode: Node = null;
    @property(Node)
    gameCompleteNode: Node = null;

    protected onLoad(): void {
        director.preloadScene(GAME_SCENE_ENUM.MENU);
        CHANGE_BOARD.on(GAME_EVENT_ENUM.CHANGE_BOARD, this.onBoardChange, this);
        CHECK_CLEAR.on(GAME_EVENT_ENUM.CHECK_CLEAR, this.onClearCheck, this);
        CHECK_LOSED.on(GAME_EVENT_ENUM.CHECK_LOSED, this.onLosedCheck, this);
        CHECK_COMPLETE.on(GAME_EVENT_ENUM.CHECK_COMPLETE, this.onCompleteCheck, this);
        this.gameStart();
    }

    protected onDestroy(): void {
        CHANGE_BOARD.off(GAME_EVENT_ENUM.CHANGE_BOARD, this.onBoardChange, this);
        CHECK_CLEAR.off(GAME_EVENT_ENUM.CHECK_CLEAR, this.onClearCheck, this);
        CHECK_LOSED.off(GAME_EVENT_ENUM.CHECK_LOSED, this.onLosedCheck, this);
        CHECK_COMPLETE.off(GAME_EVENT_ENUM.CHECK_COMPLETE, this.onCompleteCheck, this);
    }

    //开始游戏
    gameStart() {
        DataManager.instance.resotre();
        //初始化
        this.initGame(DataManager.instance.level)
        //游戏状态
        DataManager.instance.gameStatus = GAME_STATUS_ENUM.RUNNING;


    }

    //初始化游戏
    initGame(num: number) {
        let typeArr: number[] = []

        let currentLevel = levels[num - 1];
        if (!currentLevel) {
            if (levels[0]) {
                num = 1;
                DataManager.instance.level = num;
                currentLevel = levels[0];
            } else {
                return
            }
        }
        //设置当前关卡数据
        DataManager.instance.currentLevel = currentLevel;
        //更新标显示当前关卡
        this.titleLabel.string = `第${num}关`;

        //计算总块数BLOCK
        //block计算的结果是当前关卡可以被清除块的最小单位
        const blockUnit = currentLevel.clearbaleNum * currentLevel.blockTypeNum;
        //计算总块数
        let totalBlockNum = currentLevel.leftRandomBlocks + currentLevel.RightRandomBlocks + currentLevel.levelNum * currentLevel.levelBolcNum;
        if (totalBlockNum % blockUnit != 0) {
            totalBlockNum = (Math.floor(totalBlockNum / blockUnit) + 1) * blockUnit;
        }
        //获取当前关卡块的子集
        const contentTarget = currentLevel.blockTypeArr.slice(0, currentLevel.blockTypeNum);

        //根据总块数和房钱关卡的块类型数量,循环填充typeArr数组
        for (let i = 0; i < totalBlockNum; i++) {
            typeArr.push(contentTarget[i % currentLevel.blockTypeNum]);
        }

        //调用 API进行打乱数组的顺序
        typeArr = shuffle(typeArr);

        //卡牌数组
        const blockArr: BlockType[] = [];

        for (let i = 0; i < totalBlockNum; i++) {
            blockArr.push({
                id: i,
                x: null,
                y: null,
                width: currentLevel.chessItemWidth * 3,
                height: currentLevel.chessItemHeight * 3,
                level: 0,
                boardType: null, //0:普通块 1:左随机块 2:又随机块
                type: typeArr[i],
                higherIds: [],//被哪些Block压着
                lowerIds: [],//压在哪些Block上
            } as BlockType)
        }

        //作为块对象数组(blockArr)中的所有,用于跟踪我们正在处理的块
        let pos = 0;

        /**
         * 1.检查当前关卡的左右随机方块数是否为0,且关卡的总方块可消除方块数整除
         *  并且关卡总方块数可被消除方块数于方块消除种类的积整除
         *  关卡层方块数是否小于等于16
         */
        let isRandom = true;
        if (currentLevel.leftRandomBlocks == 0 &&
            currentLevel.RightRandomBlocks == 0 &&
            currentLevel.levelBolcNum % currentLevel.clearbaleNum == 0 &&
            currentLevel.levelBolcNum <= 16 &&
            (currentLevel.levelNum * currentLevel.levelBolcNum) % (currentLevel.clearbaleNum * currentLevel.blockTypeNum) == 0
        ) {
            isRandom = false;
        }

        //初始化棋盘(返回二维数组)
        let chessBox = this.initChessBox(currentLevel.chessWidthNumber, currentLevel.chessHeightNumber);
        let chessBlocks: BlockType[] = [];
        //初始化关卡区域中的块 (总共的随机块数-左侧的随机块数-右侧的随机块数)
        let remainBlockNum = totalBlockNum; - currentLevel.leftRandomBlocks - currentLevel.RightRandomBlocks;
        //利用剩下的块按层组合
        let minwidth = 0,
            maxWidth = currentLevel.chessWidthNumber - 2,
            minHeight = 0,
            maxHeight = currentLevel.chessHeightNumber - 2;
        for (let i = 0; i < currentLevel.levelNum; i++) {
            let blockNum = Math.min(currentLevel.levelBolcNum, remainBlockNum);
            //到最后一层
            if (currentLevel.levelNum - 1 == i) blockNum = remainBlockNum;
            //边界收缩业务逻辑
            if (currentLevel.blockBorderStep > 0 && i > 0) {
                //4个方法
                switch (i % 4) {
                    case 0:
                        minwidth += currentLevel.blockBorderStep;
                        break;
                    case 3:
                        maxWidth -= currentLevel.blockBorderStep;
                        break;
                    case 2:
                        minHeight += currentLevel.blockBorderStep;
                        break;
                    case 1:
                        maxHeight -= currentLevel.blockBorderStep;
                        break;
                }
            }
            //获取块
            const blocks = blockArr.slice(pos, pos + blockNum);
            pos += blockNum;

            //生成block块坐标
            let blockPosSet = new Set<string>();
            //遍历所有当前层的块,为每个块生成坐标位置
            for (let j = 0; j < blockNum; j++) {
                let block = blocks[j];
                let nx: number,
                    ny: number,
                    key: string;
                if (isRandom) {
                    //根据边界情况生成随机坐标
                    nx = Math.floor(Math.random() * (maxWidth - minwidth + 1) + minwidth);
                    ny = Math.floor(Math.random() * (maxHeight - minHeight + 1) + minHeight);
                    key = `${nx}_${ny}`;
                    //如果当前循环的块出现重叠
                    if (blockPosSet.has(key)) {
                        //重新重复循环出不重叠的坐标
                        while (true) {
                            nx = Math.floor(Math.random() * (maxWidth - minwidth + 1) + minwidth);
                            ny = Math.floor(Math.random() * (maxHeight - minHeight + 1) + minHeight);
                            key = `${nx}_${ny}`;
                            if (!blockPosSet.has(key)) break;
                        }
                    }
                } else {//有规律生成的关卡
                    //计算当前层的LevelslockNUm的平方根并且向下取整
                    let sqrt = Math.floor(Math.sqrt(currentLevel.levelBolcNum));
                    nx = j % sqrt * 4 + Math.floor(currentLevel.chessWidthNumber - 3 * sqrt) / 2;
                    


                }
            }




            remainBlockNum -= blockNum;
            if (remainBlockNum <= 0) break;
        }
    }

    //初始化棋盘
    initChessBox(width: number, height: number) {
        //创建一个二维数组
        let box = new Array(width)
        //遍历宽高
        for (let i = 0; i < width; i++) {
            //初始化每一行
            box[i] = new Array(height)
            for (let j = 0; j < height; j++) {
                box[i][j] = { blocks: [] }
            }
        }
        return box;
    }


    //重置游戏
    onGameRestart() {

    }
    //下一关
    onGameNext() {

    }

    //#region 技能
    //移除
    onGameExtend() {

    }

    //撤销
    onGameUndo() {

    }

    //洗牌
    OnGameshuffle() {

    }

    //明牌
    OnClickable() {

    }
    //#endregion

    //#region 游戏主体业务逻辑
    //游戏通关成功
    onCompleteCheck() {

    }

    //游戏通关失败
    onLosedCheck() {

    }

    //消除 
    onClearCheck() {

    }

    //更换区位
    onBoardChange() {

    }
    //#endregion

    //返回菜单
    OnBackMenu() {

    }

}


